﻿#region [===== Using =====]
using System;
using System.Collections.Generic;
using System.Text;
#endregion

namespace TPG.SharePoint.Workflow
{
    /// <summary>
    /// Stores the modification data used by modification
    /// pages and provides automatic serialization using the 
    /// <see cref="WorkflowDataSerializer" />.
    /// </summary>
    public sealed class ModificationData
    {
        #region [===== Fields =====]
        private string _nativeData;
        #endregion

        #region [===== Properties =====]
        /// <summary>
        /// Gets the modification data in its native, serialized, form.
        /// </summary>
        public string NativeData
        {
            get { return _nativeData; }
        }
        #endregion

        #region [===== Constructor =====]
        private ModificationData(string nativeData)
        {
            _nativeData = nativeData;
        }
        #endregion

        #region [===== Public methods =====]
        /// <summary>
        /// Assign data in its native serialized form.
        /// </summary>
        /// <param name="nativeData">The serialized data.</param>
        public void AssignNativeData(string nativeData)
        {
            _nativeData = nativeData;
        }

        /// <summary>
        /// Assign data as a typed object.
        /// </summary>
        /// <typeparam name="TData">The Type of the data used.</typeparam>
        /// <param name="data">The data to store.</param>
        public void AssignTypedData<TData>(TData data) 
            where TData : class
        {
            AssignTypedData(data, SerializationMode.Xml);
        }

        /// <summary>
        /// Assigns data as a typed object, indicating the mode of 
        /// serialization to use.
        /// </summary>
        /// <typeparam name="TData">The Type of the data used.</typeparam>
        /// <param name="data">The data itself</param>
        /// <param name="serializationMode">The mode of serialization to use
        /// to convert the data to a string.</param>
        public void AssignTypedData<TData>(TData data,
            SerializationMode serializationMode)
            where TData : class
        {
            _nativeData = serializationMode == SerializationMode.Xml ?
                WorkflowDataSerializer.SerializeToXmlString(data) :
                WorkflowDataSerializer.SerializeToBase64String(data);
        }

        /// <summary>
        /// Gets the data as a typed object.
        /// </summary>
        /// <typeparam name="TData">The Type of the data used.</typeparam>
        /// <returns>The stored data.</returns>
        public TData GetTypedData<TData>() 
            where TData : class
        {
            return GetTypedData<TData>(SerializationMode.Xml);
        }

        /// <summary>
        /// Gets the data as a typed object.
        /// </summary>
        /// <typeparam name="TData">The Type of the data used.</typeparam>
        /// <param name="serializationMode">The mode of serialization to use
        /// to convert the data from a string.</param>
        /// <returns>The stored data.</returns>
        public TData GetTypedData<TData>(SerializationMode serializationMode)
            where TData : class
        {
            if (string.IsNullOrEmpty(_nativeData))
                return null;
            else
                return serializationMode == SerializationMode.Xml ?
                    WorkflowDataSerializer.DeserializeFromXmlString<TData>(_nativeData) :
                    WorkflowDataSerializer.DeserializeFromBase64String<TData>(_nativeData);
        }
        #endregion

        #region [===== Public static methods =====]
        /// <summary>
        /// Creates a new ModificationData object using a string 
        /// of serialized data.
        /// </summary>
        /// <param name="data">The data to use to create the ModificationData
        /// object.</param>
        /// <returns>The ConfigurationData object.</returns>
        public static ModificationData CreateUsingStringData(string data)
        {
            return new ModificationData(data);
        }

        /// <summary>
        /// Creates a new ModificationData object using a typed object
        /// which is automatically serialized using the XmlSerializer.
        /// </summary>
        /// <param name="data">The data to use to create the ModificationData
        /// object.</param>
        /// <typeparam name="TData">The Type of the data used.</typeparam>
        /// <returns>The ModificationData object.</returns>
        public static ModificationData CreateUsingTypedData<TData>(TData data) where TData : class
        {
            return CreateUsingTypedData<TData>(data, SerializationMode.Xml);
        }

        /// <summary>
        /// Creates a new ModificationData object.
        /// </summary>
        /// <param name="data">The data to use to create the ConfigurationData
        /// object.</param>
        /// <param name="serializationMode">The mode of serialization to use
        /// to convert the data to a string.</param>
        /// <typeparam name="TData">The Type of the data used.</typeparam>
        /// <returns>The ModificationData object.</returns>
        public static ModificationData CreateUsingTypedData<TData>(TData data,
            SerializationMode serializationMode)
            where TData : class
        {
            if (data == null)
                throw new ArgumentNullException("data");
            return serializationMode == SerializationMode.Xml ?
                new ModificationData(
                    WorkflowDataSerializer.SerializeToXmlString(data)) :
                new ModificationData(
                    WorkflowDataSerializer.SerializeToBase64String(data));
        }
        #endregion
    }
}
